package com.ssy.lingxi.component.redis.lock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * redis锁模板方法
 * @author yzc
 * @version 2.0.0
 * @date 2021/7/15
 */
public class LockTemplate {

    private static final Logger log = LoggerFactory.getLogger(LockTemplate.class);

    private final RedisLockExecutor lockExecutor;

    public LockTemplate(RedisLockExecutor lockExecutor) {
        this.lockExecutor = lockExecutor;
    }

    public LockInfo lock(String key) {
        return lock(key, 0, -1);
    }

    /**
     * 加锁方法
     *
     * @param key            锁key 同一个key只能被一个客户端持有
     * @param expire         过期时间(ms) 防止死锁
     * @param acquireTimeout 尝试获取锁超时时间(ms)
     * @return 加锁成功返回锁信息 失败返回null
     */
    public LockInfo lock(String key, long expire, long acquireTimeout) {
        expire = expire <= 0 ? LockConstant.expire : expire;
        acquireTimeout = acquireTimeout < 0 ? LockConstant.acquireTimeout : acquireTimeout;
        long retryInterval = LockConstant.retryInterval;

        int acquireCount = 0;
        String value = this.simpleUUID();
        long start = System.currentTimeMillis();
        try {
            do {
                acquireCount++;
                String lockInstance = lockExecutor.acquire(key, value, expire, acquireTimeout);
                if (null != lockInstance) {
                    return new LockInfo(key, value, expire, acquireTimeout, acquireCount, lockInstance,
                            lockExecutor);
                }
                TimeUnit.MILLISECONDS.sleep(retryInterval);
            } while (System.currentTimeMillis() - start < acquireTimeout);
        } catch (InterruptedException e) {
            log.error("lock error", e);
            throw new LockException();
        }
        return null;
    }

    /**
     * 释放锁方法
     * @param lockInfo 锁信息
     * @return 成功true, 失败false
     */
    public boolean releaseLock(LockInfo lockInfo) {
        if (null == lockInfo) {
            return false;
        }
        return lockExecutor.releaseLock(lockInfo.getLockKey(), lockInfo.getLockValue(),
                lockInfo.getLockInstance());
    }

    /**
     * 去除-的uuid
     *
     * @return simpleUUID
     */
    private String simpleUUID() {
        return UUID.randomUUID().toString().replace("-", "");
    }


}
